package de.herberlin.server.httpd;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;

import de.herberlin.server.common.*;
import de.herberlin.server.common.ConfigConstants;
import de.herberlin.server.common.Configuration;
import de.herberlin.wwwutil.SimpleResponse;
import de.herberlin.wwwutil.httperror.ConnectionLost;
import de.herberlin.wwwutil.httperror.HttpError;
import de.herberlin.wwwutil.httperror.MovedTemporarily_302;

/**
 * Handles a directory list.
 * @author hans joachim herbertz
 * created 28.01.2004
 */
public class DirectoryListHttpHandler extends BasicHttpHandler {

	/**
	 * @param data
	 */
	public DirectoryListHttpHandler(HttpData data) {
		super(data);
	}

	/**
	 * Filter for default files to be displayed if 
	 * a directory is requested e.g. index.html etc.
	 */
	class DefaultFileFilter implements FilenameFilter {

		private String[] accept = null;

		/**
		 * Accepted files is expected to be a commaseparated
		 * string of names, e.g. "index.html,index.php,default.asp";
		 * @param acceptedFiles
		 */
		DefaultFileFilter(String acceptedFiles) {
			if (acceptedFiles == null) {
				throw new RuntimeException("AcceptedFiles may not be null.");
			}
			accept = acceptedFiles.split(",");
			for (int i = 0; i < accept.length; i++) {
				accept[i] = accept[i].trim();
			}
		}

		/**
		 * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
		 */
		public boolean accept(File dir, String name) {
			if (name == null) {
				return false;
			}
			for (int i = 0; i < accept.length; i++) {
				if (name.equals(accept[i])) {
					return true;
				}
			}
			return false;
		}
	}

	/**
	 * @see de.herberlin.server.BasicHttpHandler#perform()
	 */
	public void perform() throws HttpError {
		String defaultPage = getDefaultPage(data.realPath);

		if (defaultPage != null) {

			if (data.req.getPath().endsWith("/")) {
				throw new MovedTemporarily_302(data.req.getPath() + defaultPage);
			} else {
				throw new MovedTemporarily_302(
                data.req.getPath() + "/" + defaultPage);
			}

		} else if (data.req.getPath().endsWith("/")) {

			listDirectory(data);

		} else {

			// directory list
			throw new MovedTemporarily_302(data.req.getPath() + "/");
		}

	}

	/**
	 * Returns the default page for a given directory 
	 * or null if a suitable page is not present or 
	 * default pages must not be shown.
	 */
	private String getDefaultPage(File pathIsDirectory) {
		if (Configuration
			.getPrefs()
			.getBoolean(ConfigConstants.HTTP_USE_DEFAULT_PAGES, true)) {

			// finding a default page
			String[] allFiles =
				pathIsDirectory.list(
					new DefaultFileFilter(
						Configuration.getPrefs().get(
							ConfigConstants.HTTP_DEFAULT_PAGE_LIST,
							"index.htm,index.html,index.shtml")));
			if (allFiles.length > 0) {
				logger.fine("Default page found: " + allFiles[0]);
				return allFiles[0];
			}
		}
		logger.fine("Default page not found.");
		return null;
	}

	/**	Shows a directory list	*/
	private void listDirectory(HttpData data) throws ConnectionLost {

		File[] allFiles = data.realPath.listFiles();

		data.resp = new SimpleResponse();
		data.resp.setHeader("Content-Type", "text/html");
		data.resp.setHeader("Connection", "close");
		moreHeaders(data.resp);
		try {
			data.resp.write(data.out);
			data.out.flush();
		} catch (HttpError e) {
			logger.throwing(getClass().getName(), "listDirectory", e);
		} catch (IOException e) {
			ConnectionLost ex = new ConnectionLost(e);
			logger.throwing(getClass().getName(), "listDirectory", ex);
			throw ex;
		}

		StringBuffer buffer = new StringBuffer();
		buffer.append(
			"<html><head><title>Directory List</title></head>\n<body ><h1>");
		buffer.append(Configuration.getPrefs().get("host", "localhost"));
		buffer.append(":");
		buffer.append(data.port);
		buffer.append(data.req.getPath());
		buffer.append("</h1>\n");
		buffer.append(
			"<p><a href=\"../\">parent dir</a></p> \n<ul type=\"circle\" > \n");
		for (int i = 0; i < allFiles.length; i++) {
			if (allFiles[i].isDirectory())
				buffer.append(
					"<li><a href=\""
						+ allFiles[i].getName()
						+ "/\">"
						+ allFiles[i].getName()
						+ "</a></li>\n");
		}
		buffer.append("</ul><ul type=\"square\">\n");
		for (int i = 0; i < allFiles.length; i++) {
			if (!allFiles[i].isDirectory())
				buffer.append(
					"<li><a href=\""
						+ allFiles[i].getName()
						+ "\">"
						+ allFiles[i].getName()
						+ "</a></li>\n");
		}
		buffer.append("</ul></body></html>");

        
		try {
			writePaused(
				new ByteArrayInputStream(buffer.toString().getBytes()),
				data.out,
				pause);
		} catch (IOException e) {
			ConnectionLost ex = new ConnectionLost(e);
			logger.throwing(getClass().getName(), "listDirectory", ex);
			throw ex;
		}

        // set file data        
        data.fileData.setContentType("text/html");
        data.fileData.setContentLength(buffer.length());
        data.fileData.setData(buffer.toString().getBytes());
        data.fileData.setContentDescription("Directory: "+data.realPath);
        

		logger.fine("ListDirectory done for " + data.req.getPath());

	}

}
